module GYLite {
	export class AtlasRect extends egret.Rectangle implements GYLite.IPoolObject{
		/**创建虚拟图集区域
		 * @param x 区域左上角x
		 * @param y 区域左上角y
		 * @param w 区域宽度
		 * @param h 区域高度
		 * @param parent 父级区域
		 * @return AtlasRect区域
		*/
		public static createAtlasRect(x:number,y:number,w:number,h:number,parent:AtlasRect):AtlasRect
		{
			let r:AtlasRect;
			r = <AtlasRect>GYLite.PoolUtil.fromPool(AtlasRect);
			r.setTo(x,y,w,h);
			if(parent)
			{
				r.$parent = parent;
				r.copyAtlasProp(parent);
			}			
			return r;
		}
		public static maxSize:number=1024;
		public static minSize:number=4;

		public emptyRects:Array<AtlasRect>;
		public textureRects:Array<AtlasRect>;
		/**图集名称*/public atlasName:string;
		/**id*/public atlasId:number;
		public gap:number;

		public $childVec:Array<AtlasRect>;
		public $parent:AtlasRect;
		/**小图纹理名称*/public name:string;		
		/**纹理宽度，空白区域此属性为NaN*/
		public textureWidth:number;
		/**纹理高度，空白区域此属性为NaN*/
		public textureHeight:number;
		private _mgr:AtlasManager;
		/**创建虚拟图集区域
		 * @param x 区域左上角x
		 * @param y 区域左上角y
		 * @param w 区域宽度
		 * @param h 区域高度
		 * @param mgr 图集管理器，只有主图集有管理器的引用		 
		*/
		public constructor(x:number=0,y:number=0,w:number=0,h:number=0,mgr:AtlasManager=null) {
			super(x,y,w,h);
			let s = this;
			s.gap = 0;
			s.$childVec = [];
			s._mgr = mgr;
			s.textureWidth = s.textureHeight = NaN;
		}
		/**虚拟图集管理器*/
		public get mgr():AtlasManager
		{
			return this._mgr;
		}
		/**图集资源唯一键 图集名称+id(id其实也是唯一的)*/
		public get resKey():string
		{
			return this.atlasName + "_" + this.atlasId;
		}
		/**添加空白区域*/
		public addEmptyRect(atlasRect:AtlasRect):void
		{
			let s= this;
			s.emptyRects.push(atlasRect);
			s.$childVec.push(atlasRect);
		}
		/**添加纹理区域*/
		public addTextureRect(atlasRect:AtlasRect):void
		{
			let s= this;
			s.textureRects.push(atlasRect);
			s.$childVec.push(atlasRect);
		}
		/**拷贝引用父级图集的内容(因此内容共享于最外层主图集)*/
		public copyAtlasProp(rect:AtlasRect):void
		{
			let s = this;
			s.emptyRects = rect.emptyRects;
			s.textureRects = rect.textureRects;
			s.atlasName = rect.atlasName;
			s.atlasId = rect.atlasId;
		}
		public findTextureRect(texName:string):AtlasRect
		{
			let len:number;
			let s =this;
			len = s.textureRects.length;
			while(--len > -1)
			{
				if(s.textureRects[len].name == texName)
					return s.textureRects[len];
			}
			return null;
		}
		/**裁切出指定宽高的空白区域
		 * @param w 宽度（不包括间隙）
		 * @param h 高度（不包括间隙）
		 * @param type 裁剪策略 排列方式0 偏向正方形 1 优先横向 2 优先纵向
		 * @param gap 间隙
		 * @return 空间不足返回null，裁切成功返回AtlasRect（其中宽高是包括间隙的）
		*/
		public cutRect(w:number,h:number,type:number=0,gap:number=1):AtlasRect
		{let s = this;
			var ind:number,len:number;
			var rect:AtlasRect;
			let sW:number,sH:number;
			let suitableRect:AtlasRect;
			let minCp:number,min:number = Number.MAX_VALUE;						
			sW = w + gap*2;
			sH = h + gap*2;
			len = s.emptyRects.length;
			while(--len > -1)
			{
				rect = s.emptyRects[len];
				if(rect.width >= sW && rect.height >= sH)
				{
					minCp = Math.min(rect.width - sW,rect.height - sH);
					if(minCp < min)
					{
						suitableRect = rect;
						min = minCp;
						ind = len;
					}
						
				}
			}
			if(suitableRect)
				return suitableRect.getClipRect(w,h,ind,type,gap)
			return null;
		}
		private getClipRect(w:number,h:number,ind:number,type:number=0,gap:number=1):AtlasRect
		{let s = this;
			var r:AtlasRect;
			var child1:AtlasRect,child2:AtlasRect;
			var leftW:number,leftH:number;
			let sW:number,sH:number;			
			sW = w + gap*2;
			sH = h + gap*2;			
			r = AtlasRect.createAtlasRect(s.x,s.y,sW,sH,s);
			r.gap = gap;
			// r = <AtlasRect>GYLite.PoolUtil.fromPool(AtlasRect);
			// r.setTo(s.x,s.y,sW,sH);
			r.textureWidth = w;
			r.textureHeight = h;
			leftW = s.width - sW;
			leftH = s.height - sH;
			if(type == 1 || type == 0 && leftW < leftH)
			{
				if(leftW > AtlasRect.minSize)
				{
					child1 = AtlasRect.createAtlasRect(r.right,r.y,leftW,sH,s);
					// child1 = <AtlasRect>GYLite.PoolUtil.fromPool(AtlasRect);
					// child1.setTo(r.right,r.y,leftW,sH);
				}
				if(leftH > AtlasRect.minSize)
				{
					child2 = AtlasRect.createAtlasRect(r.x,r.bottom,s.width,leftH,s);
					// child2 = <AtlasRect>GYLite.PoolUtil.fromPool(AtlasRect);
					// child2.setTo(r.x,r.bottom,s.width,leftH);
				}
			}
			else
			{
				if(leftH > AtlasRect.minSize)
				{
					child1 = AtlasRect.createAtlasRect(r.x,r.bottom,sW, leftH,s);
					// child1 = <AtlasRect>GYLite.PoolUtil.fromPool(AtlasRect);
					// child1.setTo(r.x,r.bottom,sW, leftH);
				}
				if(leftW > AtlasRect.minSize)
				{
					child2 = AtlasRect.createAtlasRect(r.right,r.y,leftW, s.height, s);
					// child2 = <AtlasRect>GYLite.PoolUtil.fromPool(AtlasRect);
					// child2.setTo(r.right,r.y,leftW, s.height);
				}
			}
			// r.parent = s;			
			// r.copyAtlasProp(s);			
			s.textureRects.push(r);
			s.$childVec.push(r);			
			if(child1)
			{
				// child1.parent = s;
				// child1.copyAtlasProp(s);
				s.$childVec.push(child1);				
				s.emptyRects[ind] = child1;
			}
			if(child2)
			{
				// child2.parent = s;
				// child2.copyAtlasProp(s);				
				s.$childVec.push(child2);				
				if(child1 == null)
					s.emptyRects[ind] = child2;
				else
					s.emptyRects.push(child2);
			}
			if(child1 == null && child2 == null)
				s.emptyRects.splice(ind,1);
			return r;
		}
		/**请求回到空白队列*/
		public backToEmpty():AtlasRect
		{let s = this;
			var len:number;
			var vec:Array<AtlasRect>;
			var c1:AtlasRect,c2:AtlasRect;
			var p:AtlasRect = s.$parent;
			if(p == null || p.$childVec.length > 2)//没有父级或者父级的子对象超过2个则认为是不需要往上递归恢复
			{
				s.name = null;
				var ind:number = s.textureRects.indexOf(s);
				if(ind > -1)
					s.textureRects.splice(ind,1);
				s.emptyRects.push(s);
				return s;
			}
			vec = p.$childVec;
			len = vec.length;
			while(--len>-1)
			{
				if(s == vec[len])continue;
				if(vec[len].isUse())
				{
					s.name = null;
					var ind:number = s.textureRects.indexOf(s);
					if(ind > -1)
						s.textureRects.splice(ind, 1);
					s.emptyRects.push(s);
					return s;
				}			
				if(c1==null)
					c1 = vec[len];
				else
					c2 = vec[len];
				
			}
			c1 && c1.clear();
			c2 && c2.clear();
			s.clear();
			vec.length = 0;
			return p.backToEmpty();
		}		
		
		/**是否已经填充图集*/
		public isTexture():boolean
		{
			return this.name != null;
		}
		/**是否已经被裁切使用*/
		public isUse():Boolean
		{let s = this;
			return s.$childVec.length > 0 || s.name != null;
		}
		/**输出图集配置*/
		public outputJson():any
		{
			let s = this;
			let obj:any = {};
			obj.name = s.name;
			obj.altasId = s.atlasId;
			obj.atlasName = s.atlasName;
			obj.gap = s.gap;
			obj.textureWidth = s.textureWidth;
			obj.textureHeight = s.textureHeight;
			obj.x = s.x;
			obj.y = s.y;
			obj.width = s.width;
			obj.height = s.height;
			obj.childVec = [];
			let i:number,len:number;
			len = s.$childVec.length;
			for(i=0;i<len;++i)
			{
				obj.childVec.push(s.$childVec[i].outputJson());
			}
			return obj;
		}
		/**输入图集配置*/
		public inputJson(obj:any):void
		{
			let s = this;
			let rect:AtlasRect;
			s.name = obj.name;
			s.atlasId = obj.altasId;
			s.atlasName = obj.atlasName;
			s.gap = obj.gap;
			s.textureWidth = obj.textureWidth;
			s.textureHeight = obj.textureHeight;
			s.x = obj.x;
			s.y = obj.y;
			s.width = obj.width;
			s.height = obj.height;			
			let i:number,len:number;
			len = obj.childVec.length;
			for(i=0;i<len;++i)
			{
				rect = <AtlasRect>GYLite.PoolUtil.fromPool(AtlasRect);
				rect.$parent = s;
				rect.copyAtlasProp(s);
				rect.inputJson(obj.childVec[i]);
				s.$childVec.push(rect);
			}
			if(s.name)
				s.textureRects.push(s);
			else if(!s.isUse())
				s.emptyRects.push(s);
		}
		public inPool:boolean;
		protected beforeToPool():void
		{
			let s= this;
			var ind:number = s.emptyRects.indexOf(this);
			if(ind > -1)
				s.emptyRects.splice(ind,1);
			var ind:number = s.textureRects.indexOf(this);
			if(ind > -1)
				s.textureRects.splice(ind,1);
			s.$parent = null;
			s.atlasName = s.name = null;
			s.atlasId = -1;
			s.gap = 0;
			s.textureWidth = s.textureHeight = NaN;
			if(s._mgr)
			{
				s._mgr.removeAtlas(s);
				s._mgr = null;
			}
		}
		public clear(): void
		{
			let s = this;
			if(s.inPool)
				return;
			s.beforeToPool();
			GYLite.PoolUtil.toPool(this,AtlasRect);
		}		
        public outPoolInit(): void
		{

		}
        public dispose(): void
		{
			let s= this;
			s.beforeToPool();
		}
	}
}